﻿using FluentFTP;
using System;
using System.IO;

namespace CommonLibrary.Utils
{
    public class CommonFTP : IDisposable
    {
        private FtpClient FTP;
        public bool Connected { get; private set; }
        public string IP { get; private set; }
        public int Port { get; private set; }
        public string User { get; private set; }
        public string Passwd { get; private set; }

        public string FtpRootPath { get; set; }
        public string LocalBasePath { get; set; }

        public CommonFTP(string ip, string user, string passwd, int port = 21)
        {
            IP = ip;
            Port = port;
            User = user;
            Passwd = passwd;
            FTP = new FtpClient(IP, User, Passwd, Port);
        }

        public void Connect()
        {
            FTP.Connect();
            Connected = FTP.IsConnected;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="file"></param>
        /// <param name="localBasePath"></param>
        /// <param name="ftpRootPath"></param>
        /// <returns></returns>
        /// <exception cref="FileNotFoundException"></exception>
        public bool UploadFile(string file, string localBasePath = null, string ftpRootPath = null)
        {
            file = file.Replace("\\", "/");
            if (!File.Exists(file))
                throw new FileNotFoundException(file);

            if (string.IsNullOrWhiteSpace(localBasePath))
                localBasePath = LocalBasePath;
            if (string.IsNullOrWhiteSpace(ftpRootPath))
                ftpRootPath = FtpRootPath;

            localBasePath = localBasePath.Replace("\\", "/");
            ftpRootPath = ftpRootPath.Replace("\\", "/");

            string relativeFile = file.Replace(localBasePath, string.Empty);
            if (relativeFile.StartsWith("/"))
                relativeFile = relativeFile.Substring(1);

            string ftpFilePath = Path.Combine(ftpRootPath, relativeFile);
            string fileName = Path.GetFileName(file);
            string ftpUploadPath = ftpFilePath.Replace(fileName, string.Empty);
            FtpMakeDirectory(ftpUploadPath, ftpRootPath);

            if (FTP.FileExists(ftpFilePath))
                return true;

            using FileStream stream = File.OpenRead(file);
            var status = FTP.UploadStream(stream, ftpFilePath);
            return status == FtpStatus.Success;
        }

        /// <summary>
        /// 创建文件夹
        /// </summary>  
        /// <param name="createPath">待创建路径</param>  
        /// <param name="basePath">基础路径</param>  
        public bool FtpMakeDirectory(string createPath, string basePath)
        {
            if (CheckFtpDirectoryExist(createPath))
                return true;

            bool exeRs = false;
            createPath = createPath.Replace(@"\", "/");
            basePath = basePath.Replace(@"\", "/");
            string relativeCreatePath = createPath.Replace(basePath, string.Empty);
            if (relativeCreatePath.StartsWith("/"))
                relativeCreatePath = relativeCreatePath.Substring(1);

            try
            {
                string[] subDirs = relativeCreatePath.Split('/');
                string curPath = basePath;
                foreach (string subDir in subDirs)
                {
                    if (string.IsNullOrWhiteSpace(subDir)) { continue; }

                    curPath = Path.Combine(curPath, subDir).Replace(@"\", "/");
                    if (!CheckFtpDirectoryExist(curPath))
                    {
                        if (!FTP.CreateDirectory(curPath))
                            return false;
                    }
                }

                exeRs = true;
            }
            catch (Exception ex)
            {
                throw;//CommonLog.LogError(ex, $"新建文件夹[{createPath}]时，发生错误");
            }
            return exeRs;
        }


        /// <summary>
        /// 判断ftp服务器上该目录是否存在
        /// </summary>
        /// <param name="ftpPath">FTP路径目录/目录上的文件夹名称</param>
        /// <returns></returns>
        public bool CheckFtpDirectoryExist(string ftpPath) => FTP.DirectoryExists(ftpPath);

        #region Dispose
        private bool disposedValue;

        protected virtual void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing)
                {
                    // TODO: 释放托管状态(托管对象)
                    FTP?.Dispose();
                    FTP = null;
                }

                // TODO: 释放未托管的资源(未托管的对象)并重写终结器
                // TODO: 将大型字段设置为 null
                disposedValue = true;
            }
        }

        public void Dispose()
        {
            // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
            Dispose(disposing: true);
            GC.SuppressFinalize(this);
        }
        #endregion

    }
}
